﻿
namespace Patterns4Net.Core.CecilExtensions
{
    using System;
    using System.Diagnostics.Contracts;
    using Mono.Cecil;

    public class MethodCall
    {
        public MethodCall(MethodReference method, StackItem targetObject, StackItem[] parameters)
        {
            Contract.Requires(method != null);
            Contract.Requires(parameters != null);
            Contract.Ensures(this.Method == method);
            Contract.Ensures(targetObject == null || this.TargetObject == targetObject);
            Contract.Ensures(targetObject == null || this.HasTargetObject);
            Contract.Ensures(this.Parameters == parameters);
            this.Method = method;
            this.targetObject = targetObject;
            this.Parameters = parameters;
        }

        public MethodReference Method { get; private set; }

        private StackItem targetObject;

        /// <summary>
        /// Gets the object on which the <see cref="Method"/> was called.
        /// If the method is static, then this will be null.
        /// </summary>
        public StackItem TargetObject
        {
            get
            {
                if (this.targetObject == null)
                {
                    throw new InvalidOperationException(
                        "MethodCall: the TargetObject is not available for static method calls. " + 
                        "Before accessing the TargetObject property, test the HasTarget property.");
                }

                return this.targetObject;
            }
        }

        public bool HasTargetObject
        {
            get { return this.targetObject != null; }
        }

        public StackItem[] Parameters { get; private set; }

        [ContractInvariantMethod]
        private void Invariant()
        {
            Contract.Invariant(this.Parameters != null);
            Contract.Invariant(this.Method != null);
        }
    }
}
